package com.rpc.dubboRpcError.netty;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.concurrent.Callable;

/**
 * @author 何章怀晓 hezhanghuaixiao
 * @version V1.0
 * @desc
 */
public class NettyClientHandler
    extends ChannelInboundHandlerAdapter
    implements Callable {

  private ChannelHandlerContext channelHandlerContext;

  private String fatureResult;

  private String para;

  //执行顺序
  //para被设置参数
  //Active连接触发
  //call发送消息到服务器
  //channelRead0服务器返回
  //call继续执行


  //服务器连接后即调用
  //与服务端创建连接后调用
  @Override
  public void channelActive(ChannelHandlerContext ctx) throws Exception {

    channelHandlerContext = ctx; //因为我们在其他方法会使用到 ctx

    System.out.println("通道连接成功" + channelHandlerContext.toString());
  }

  //被代理对象调用，发送数据到server端，发送后立即阻塞等待被唤醒

  @Override
  public synchronized Object call() throws Exception {
    System.out.println("call 被调用 + para:" + para);
    //调用服务器端
    channelHandlerContext.writeAndFlush(para);
    wait();
    System.out.println("call--->result:" + fatureResult);
    return fatureResult;
  }

  //收到服务器数据后被调用
  //该方法和call是同步关系，两个方法的执行时机必须连贯并不被其他线程打乱


  @Override
  public synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    System.out.println("回调客户端");
    fatureResult = msg.toString();
    //唤醒等待线程，那么线程在哪里阻塞的呢？
    //执行call远程调用，线程阻塞，但是返回的结果直接到这里（netty机制），故需唤醒call中的阻塞线程，继续执行
    //简单理解：一般的调用直接返回到当前方法，netty机制的特殊性，返回到另一个方法中
    notifyAll();
  }

  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
      throws Exception {
    cause.printStackTrace();
    ctx.close();
  }


  public void setPara(String para) {
    this.para = para;
  }


}
